<?php
namespace Swostar\Container;

use Exception;
/**
 * 容器类
 * @package Swostar\Container
 */
class Container
{
    // 实例 单例
    public static $instance;

    // 需要容器
    protected $bindingArray = [];
    protected $instanceArray = [];

    // 创建单例
    public static function getInstance() 
    {
        if (is_null(static::$instance)) {
            static::$instance = new static;
        }

        return static::$instance;
    }

    public static function setInstance($container = null)
    {
        return static::$instance = $container;
    }

    /**
     * 绑定对象到容器
     * @param string $abstract 标识
     * @param object|callback $object 实例对象或者闭包 
     * @return void 
     */
    public function bind(string $abstract, $object)
    {
        $this->bindingArray[$abstract] = $object;
    }


    public function make(string $abstract, $parameters = [])
    {
        return $this->resolve($abstract, $parameters);
    }

    /**
     * 从容器中获取对象
     * @param string $abstract 标识
     * @param array $parameters 传入参数
     * @return object 
     * @throws Exception 
     */
    protected function resolve(string $abstract, $parameters = [])
    {
        if (isset($this->instanceArray[$abstract])) {
            return $this->instanceArray[$abstract];
        }

        if (!$this->has($abstract)) {
            throw new Exception('容器中没有找到这个对象'.$abstract, 500);
        }

        $object = $this->bindingArray[$abstract];

        // 如果是闭包函数，则执行函数
        if ($object instanceof \Closure) {
            return $object();
        }

        // 判断是否为对象
        // 1. 对象直接返回，
        // 2. 非对象（类的地址、命名空间），new后赋值
        if (is_object($object)) {
            $this->instanceArray[$abstract] = $object;
        } else {
            $this->instanceArray[$abstract] = new $object(...$parameters);
        }

        return $this->instanceArray[$abstract];
    }

    /**
     * 判断是否绑定到容器中
     * @param string $abstract 标识
     * @return bool 
     */
    public function has(string $abstract)
    {
        return isset($this->bindingArray[$abstract]);
    }

}
